#include "mainwindow.h"

#include <QDebug>
#include <QFile>
#include <QFileDialog>
#include <QStandardItem>
#include <QStandardItemModel>
#include <QToolButton>

#include "../config_wizard/cfg_wizard.h"
#include "../dialog/dialoggpio.h"
#include "../dialog/dialogi2c.h"
#include "../dialog/dialoglcd.h"
#include "../dialog/dialogspi.h"
#include "../dialog/dialoguart.h"
#include "../dialog/dialogspii2c.h"
#include "../dialog/dialogspisdio.h"
#include "../dialog/dialogspiqspi.h"
#include "ui_mainwindow.h"

static cfg_wizard  b_cfg_wizard;
static cfg_node_t *pselected_node = nullptr;

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QLabel *sbar_info = new QLabel();
    sbar_stat         = new QLabel();
    sbar_info->setText("http://babyos.cn");
    sbar_stat->setText("<<V0.0.4>>");

    ui->statusBar->addWidget(sbar_stat);
    ui->statusBar->addPermanentWidget(sbar_info);

    ui->tree_config->setHeaderLabel(tr("BabyOS Configuration"));
    ui->lable_bos_path->setText("");
    ui->label_config_path->setText("");
    ui->combox_opt->setVisible(false);
    ui->line_edit_opt->setVisible(false);
    ui->button_modify_sure->setVisible(false);
}

MainWindow::~MainWindow()
{
    delete ui;
}

/**
 * \brief 将得到的链表，显示在QTree控件中
 * \param dir b_config.h文件存在的路径
 * \param ptree ui界面下的QTreeWidget
 */
void MainWindow::btool_parse_cfgfile(QString dir, QTreeWidget *ptree)
{
    QTreeWidgetItem *pheaditem;
    /*******************************************************/
    QString filename = dir + "/" + "b_config.h";
    b_cfg_wizard.cfg_parse(filename);
    cfg_node_t *pcnode = b_cfg_wizard.cfg_node_head.next;
    while (pcnode != nullptr)
    {
        // 父节点为null，那么为顶层项
        if (pcnode->parent == nullptr)
        {
            pheaditem = new QTreeWidgetItem(ptree);
        }
        else
        {
            pheaditem = new QTreeWidgetItem(pcnode->parent->pitem);
        }
        //设置显示内容
        pheaditem->setText(0, b_cfg_wizard.cfg_node_title(pcnode));
        if (pcnode->parent == nullptr)
        {
            ptree->addTopLevelItem(pheaditem);
        }
        //记录当前的QTreeWidgetItem
        pcnode->pitem = pheaditem;
        //先判断是否还有子节点，再判断是否还有兄弟节点
        if (pcnode->child != nullptr)
        {
            pcnode = pcnode->child;
        }
        else if (pcnode->next != nullptr)
        {
            pcnode = pcnode->next;
        }
        else
        {
            //没有子节点和兄弟节点，那么再回到父节点进行查找
            if (pcnode->parent != nullptr)
            {
                pcnode = pcnode->parent;
                while (pcnode != nullptr)
                {
                    if (pcnode->next != nullptr)
                    {
                        pcnode = pcnode->next;
                        break;
                    }
                    else
                    {
                        //如果父节点也没有兄弟节点，再往上走
                        pcnode = pcnode->parent;
                    }
                }
            }
            else
            {
                pcnode = nullptr;
            }
        }
    }
}

/**
 * \brief 主要是解析b_driver.h里面声明的驱动，列出驱动名
 * \param dir
 */
void MainWindow::btool_parse_bos(QString dir)
{
    int     i = 0;
    QString tmp_str;
    QString filename = dir + "/" + "drivers/inc/b_driver.h";
    QFile   bos(filename);
    if (!bos.open(QIODevice::ReadOnly))
    {
        sbar_stat->setText("open " + filename + " error");
        return;
    }
    QByteArray bos_data = bos.readAll();
    bos.close();

    ui->combox_driver->clear();
    QString     bos_str   = QString::fromLatin1(bos_data);
    QStringList bos_lines = bos_str.split("\n");
    int start_flag = 0;
    for (i = 0; i < bos_lines.length(); i++)
    {
        tmp_str = bos_lines.at(i);
        if(tmp_str.contains("B_DRIVER_NULL"))
        {
            start_flag = 1;
            continue;
        }
        if(tmp_str.contains("B_DRIVER_NUMBER"))
        {
            break;
        }
        if (tmp_str.contains("B_DRIVER_") && start_flag)
        {
            tmp_str = tmp_str.trimmed();
            tmp_str = tmp_str.right(tmp_str.length() - tmp_str.lastIndexOf(' '));
            tmp_str = tmp_str.trimmed();
            tmp_str = tmp_str.left(tmp_str.indexOf(','));
            ui->combox_driver->addItem(tmp_str);
        }
    }
}

/**
 * \brief 点击控件的内容，显示对应文本
 * \param item
 * \param column
 */
void MainWindow::on_tree_config_itemClicked(QTreeWidgetItem *item, int column)
{
    int i = 0;
    // 获取被点击的文本内容
    QString     item_text = item->text(column);
    QString     tmp_str;
    cfg_node_t *pnode = nullptr;
    if (item_text.length() <= 0)
    {
        return;
    }
    // 根据文本查找匹配的节点
    for (i = 0; i < b_cfg_wizard.cfg_node_table.length(); i++)
    {
        pnode   = b_cfg_wizard.cfg_node_table.at(i);
        tmp_str = b_cfg_wizard.cfg_node_title(pnode);
        if (tmp_str.contains(item_text) == true)
        {
            pselected_node = pnode;
            break;
        }
    }

    if (pnode == nullptr)
    {
        return;
    }
    //如果是标题节点，则不处理，直接返回
    if (pnode->cfg_type == 'h')
    {
        return;
    }
    // 如果是q和e，主要是 enable 和 disable 选择
    if (pnode->cfg_type == 'q' || pnode->cfg_type == 'e')
    {
        ui->combox_opt->clear();
        ui->combox_opt->addItems({"Disable", "Enable"});
        if (pnode->cfg_type == 'q')
        {
            ui->combox_opt->setCurrentIndex(pnode->q.var_str.toInt());
        }
        else
        {
            ui->combox_opt->setCurrentIndex(pnode->e.var_str.toInt());
        }
        ui->combox_opt->setVisible(true);
        ui->line_edit_opt->setVisible(false);
        ui->button_modify_sure->setVisible(true);
    }
    else if (pnode->cfg_type == 's')
    {
        ui->combox_opt->setVisible(false);
        ui->line_edit_opt->setText(pnode->s.var_str);
        ui->line_edit_opt->setVisible(true);
        ui->button_modify_sure->setVisible(true);
    }
    else if (pnode->cfg_type == 'o')
    {
        // o 节点，根据参数的类型不同需要分别处理
        if (pnode->o.param_type == O_PARAM_NONE || pnode->o.param_type == O_PARAM_RANGE)
        {
            ui->combox_opt->setVisible(false);
            ui->line_edit_opt->setText(pnode->o.var_str);
            ui->line_edit_opt->setVisible(true);
        }
        else if (pnode->o.param_type == O_PARAM_MAP)
        {
            ui->combox_opt->clear();
            ui->combox_opt->addItems(pnode->o.param_map.keys());
            {
                ui->combox_opt->setCurrentText(pnode->o.param_map.key(pnode->o.var_str));
            }
            ui->combox_opt->setVisible(true);
            ui->line_edit_opt->setVisible(false);
            ui->button_modify_sure->setVisible(true);
        }
        ui->button_modify_sure->setVisible(true);
    }
}

/**
 * \brief 点击修改按钮后对节点的内容进行修改
 */
void MainWindow::on_button_modify_sure_clicked()
{
    if (pselected_node == nullptr)
    {
        return;
    }
    if (pselected_node->cfg_type == 'q')
    {
        pselected_node->q.var_str = ui->combox_opt->currentText().contains("Enable") ? "1" : "0";
    }
    else if (pselected_node->cfg_type == 'e')
    {
        pselected_node->e.var_str = ui->combox_opt->currentText().contains("Enable") ? "1" : "0";
    }
    else if (pselected_node->cfg_type == 's')
    {
        pselected_node->s.var_str = ui->line_edit_opt->text();
    }
    else if (pselected_node->cfg_type == 'o')
    {
        if (pselected_node->o.param_type == O_PARAM_MAP)
        {
            pselected_node->o.var_str =
                pselected_node->o.param_map.value(ui->combox_opt->currentText());
        }
        else
        {
            pselected_node->o.var_str = ui->line_edit_opt->text();
        }
    }
}

void MainWindow::on_button_config_halif_clicked()
{
    int     i       = 0;
    QString tmp_str = ui->combox_driver->currentText();
    tmp_str         = tmp_str.split('_')[2];
    drv_reg_name    = tmp_str;
    drv_halif_name  = "HAL_" + tmp_str.toUpper() + "_IF";
    tmp_str = ui->lable_bos_path->text() + "/drivers/inc/" + "b_drv_" + tmp_str.toLower() + ".h";

    QFile b_drv_file(tmp_str);
    if (!b_drv_file.open(QIODevice::ReadOnly))
    {
        sbar_stat->setText("open " + tmp_str + " error");
        return;
    }
    QByteArray drv_file_data = b_drv_file.readAll();
    b_drv_file.close();

    QStringList drv_file_lins = QString::fromLatin1(drv_file_data).split("\n");
    for (i = 0; i < drv_file_lins.length(); i++)
    {
        tmp_str = drv_file_lins.at(i).trimmed();
        if (tmp_str.contains("//<HALIF"))
        {
            break;
        }
    }
    tmp_str = tmp_str.right(tmp_str.length() - tmp_str.lastIndexOf(' ') - 1);
    create_halif_dialog(tmp_str);
}

void MainWindow::create_halif_dialog(QString halif_name)
{
    if (halif_name.contains("SPI_I2C"))
    {
        Dialogspii2c *_ifspii2c = new Dialogspii2c(this);
        connect(_ifspii2c, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifspii2c->show();
    }
    else if (halif_name.contains("SPI_QSPI"))
    {
        Dialogspiqspi *_ifspiqspi = new Dialogspiqspi(this);
        connect(_ifspiqspi, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifspiqspi->show();
    }
    else if (halif_name.contains("SPI_SDIO"))
    {
        Dialogspisdio *_ifspisdio = new Dialogspisdio(this);
        connect(_ifspisdio, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifspisdio->show();
    }
    else if (halif_name.contains("I2C"))
    {
        DialogI2C *_ifi2c = new DialogI2C(this);
        connect(_ifi2c, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifi2c->show();
    }
    else if (halif_name.contains("SPI"))
    {
        Dialogspi *_ifspi = new Dialogspi(this);
        connect(_ifspi, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifspi->show();
    }
    else if (halif_name.contains("GPIO"))
    {
        Dialoggpio *_ifgpio = new Dialoggpio(this);
        connect(_ifgpio, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifgpio->show();
    }
    else if (halif_name.contains("LCD"))
    {
        Dialoglcd *_iflcd = new Dialoglcd(this);
        connect(_iflcd, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _iflcd->show();
    }
    else if (halif_name.contains("UART"))
    {
        Dialoguart *_ifuart = new Dialoguart(this);
        connect(_ifuart, SIGNAL(send_string(QString)), this, SLOT(rec_string(QString)));
        _ifuart->show();
    }
}

void MainWindow::rec_string(QString str)
{
    QString cfg_str = "#define " + drv_halif_name + " ";
    QString reg_str = "B_DEVICE_REG(b";
    reg_str.append(drv_reg_name + "," + " B_DRIVER_" + drv_reg_name.toUpper());

    reg_str.append(", \"" + drv_reg_name.toLower() +"\")");
    cfg_str.append(str);

    ui->text_edit_code->append(cfg_str);
    ui->text_edit_code->append("\r\n\r\n");
    ui->text_edit_code->append(reg_str);
    ui->text_edit_code->append("\r\n\r\n");
}

void MainWindow::on_button_clear_clicked()
{
    ui->text_edit_code->clear();
}

/**
 * \brief 将链表内容还原成配置文件内容
 */
void MainWindow::on_button_save_config_clicked()
{
    int         i = 0;
    QString     cfg_data, file_data;
    cfg_node_t *pnode = b_cfg_wizard.cfg_node_head.next;
    cfg_data.clear();
    cfg_data.append("//<<< Use Configuration Wizard in Context Menu >>>");
    cfg_data.append("\r\n");

    while (pnode != nullptr)
    {
        if (pnode->cfg_type == 'h')
        {
            cfg_data.append("//<h> ");
            cfg_data.append(pnode->h.title);
            cfg_data.append(" \r\n");
        }
        else if (pnode->cfg_type == 'q')
        {
            cfg_data.append("//<q> ");
            cfg_data.append(pnode->q.title);
            cfg_data.append(" \n");

            cfg_data.append("#define ");
            cfg_data.append(pnode->q.var_name + ' ' + pnode->q.var_str);
            cfg_data.append(" \r\n");
        }
        else if (pnode->cfg_type == 's')
        {
            cfg_data.append("//<s> ");
            cfg_data.append(pnode->s.title);
            cfg_data.append(" \n");

            cfg_data.append("#define ");
            cfg_data.append(pnode->s.var_name + ' ' + pnode->s.var_str);
            cfg_data.append(" \r\n");
        }
        else if (pnode->cfg_type == 'e')
        {
            cfg_data.append("//<e> ");
            cfg_data.append(pnode->e.title);
            cfg_data.append(" \n");

            cfg_data.append("#define ");
            cfg_data.append(pnode->e.var_name + ' ' + pnode->e.var_str);
            cfg_data.append(" \r\n");
        }
        else if (pnode->cfg_type == 'o')
        {
            cfg_data.append("//<o> ");
            cfg_data.append(pnode->o.title);
            cfg_data.append(" \n");
            if (pnode->o.param_type == O_PARAM_MAP)
            {
                for (i = 0; i < pnode->o.param_map.keys().length(); i++)
                {
                    cfg_data.append("//<" + pnode->o.param_map.values().at(i) + "=> " +
                                    pnode->o.param_map.keys().at(i));
                    cfg_data.append(" \n");
                }
            }
            else if (pnode->o.param_type == O_PARAM_RANGE)
            {
                cfg_data.append(QString("//<%1-%2>\n")
                                    .arg(pnode->o.param_range[0])
                                    .arg(pnode->o.param_range[1]));
            }
            cfg_data.append("#define ");
            cfg_data.append(pnode->o.var_name + ' ' + pnode->o.var_str);
            cfg_data.append(" \r\n");
        }

        if (pnode->child != nullptr)
        {
            pnode = pnode->child;
        }
        else if (pnode->next != nullptr)
        {
            pnode = pnode->next;
        }
        else
        {
            if (pnode->parent != nullptr)
            {
                pnode = pnode->parent;
                if (pnode->cfg_type == 'h')
                {
                    cfg_data.append("//</h> \r\n");
                }
                else
                {
                    cfg_data.append("//</e> \r\n");
                }
                while (pnode != nullptr)
                {
                    if (pnode->next != nullptr)
                    {
                        pnode = pnode->next;
                        break;
                    }
                    else
                    {
                        pnode = pnode->parent;
                        if (pnode != nullptr)
                        {
                            if (pnode->cfg_type == 'h')
                            {
                                cfg_data.append("//</h> \r\n");
                            }
                            else
                            {
                                cfg_data.append("//</e> \r\n");
                            }
                        }
                    }
                }
            }
            else
            {
                pnode = nullptr;
                cfg_data.append("//</h> \r\n");
            }
        }
    }
    // 拼装文件数据
    file_data.clear();
    file_data.append(b_cfg_wizard.cfg_file_data[0]);
    file_data.append("\r\n\r\n");
    file_data.append(cfg_data);
    file_data.append("\r\n\r\n");
    file_data.append(b_cfg_wizard.cfg_file_data[2]);
    file_data.append("\r\n\r\n");
    // 将文件数据写入文件
    QString filename = ui->label_config_path->text() + "/" + "b_config.h";
    QFile   b_config(filename);
    if (b_config.open(QIODevice::WriteOnly))
    {
        b_config.write(file_data.toLatin1());
        b_config.close();
        sbar_stat->setText("save " + filename + " ok");
    }
    else
    {
        sbar_stat->setText("open " + filename + " error");
    }
}

/**
 * \brief 选择b_config.h所在的路径
 */
void MainWindow::on_button_select_config_clicked()
{
    QString dir = QFileDialog::getExistingDirectory(
        this, tr("选择b_config.h所在目录"), "./",
        QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    ui->label_config_path->setText(dir);
    btool_parse_cfgfile(dir, ui->tree_config);
}

/**
 * \brief 选择bos目录
 */
void MainWindow::on_button_select_bos_clicked()
{
    QString dir = QFileDialog::getExistingDirectory(
        this, tr("选择bos目录"), "./",
        QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
    ui->lable_bos_path->setText(dir);
    btool_parse_bos(dir);
}
